﻿
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// 
    /// </summary>
    public class FindContours2 : BaseImageFilter
    {
        protected int m_nColorToleranceR = 15;
        protected int m_nColorToleranceG = 15;
        protected int m_nColorToleranceB = 15;

        /// <summary>
        /// Initializes a new instance of the <see cref="FindContours2"/> class.
        /// </summary>
        public FindContours2()
            : this(15,15,15)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="FindContours2"/> class.
        /// </summary>
        /// <param name="_nR">The _n R.</param>
        /// <param name="_nG">The _n G.</param>
        /// <param name="_nB">The _n B.</param>
        public FindContours2(int _nR, int _nG, int _nB)
        {
            m_nColorToleranceR = _nR;
            m_nColorToleranceG = _nG;
            m_nColorToleranceB = _nB;
        }

        /// <summary>
        /// Find contours copy constructor used by clone to create a deep copy
        /// </summary>
        /// <param name="_findContours"></param>
        internal FindContours2(FindContours2 _findContours)
        {
            this.m_nColorToleranceR = _findContours.m_nColorToleranceR;
            this.m_nColorToleranceG = _findContours.m_nColorToleranceG;
            this.m_nColorToleranceB = _findContours.m_nColorToleranceB;
        }

        /// <summary>
        /// Gets or sets the R.
        /// </summary>
        /// <value>The R.</value>
        public int R
        {
            get { return m_nColorToleranceR; }
            set { m_nColorToleranceR = value; }
        }

        /// <summary>
        /// Gets or sets the G.
        /// </summary>
        /// <value>The G.</value>
        public int G
        {
            get { return m_nColorToleranceG; }
            set { m_nColorToleranceG = value; }
        }

        /// <summary>
        /// Gets or sets the B.
        /// </summary>
        /// <value>The B.</value>
        public int B
        {
            get { return m_nColorToleranceB; }
            set { m_nColorToleranceB = value; }
        }

        /// <summary>
        /// Todo: better detection of contours.
        /// </summary>
        /// <param name="_bitmap"></param>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            UnsafeBitmap bitmap = _bitmap;
            List<Color> aColor = new List<Color>();

            Dictionary<Point, Color> aPoint = new Dictionary<Point, Color>();
            aColor.Add(bitmap.GetPixel(0, 0));
            int nCount = 1;
            Color colorLeftDown = Color.Transparent;
            Color colorLeft = Color.Transparent;

            int nWidth = bitmap.Width;
            int nHeight = bitmap.Height;
            for (int y = 1; y < nHeight; y++)
            {
                aPoint.Clear();
                for (int x = 0; x < nWidth; x++)
                {
                    colorLeft = bitmap.GetPixel(x, y);
                    colorLeftDown = bitmap.GetPixel(x, y - 1);

                    aPoint.Add(new Point(x, y), colorLeft);
                    aColor.Add(colorLeft);
                    Color colorPrev = aColor[nCount - 1];
                    if (!ColorFunctions.IsInColorTolerance(colorLeft, colorPrev, m_nColorToleranceR, m_nColorToleranceG, m_nColorToleranceB))
                    {
                        aPoint[new Point(x, y)] = Color.Red;
                    }
                    if (!ColorFunctions.IsInColorTolerance(colorLeft, colorLeftDown, m_nColorToleranceR, m_nColorToleranceG, m_nColorToleranceB))
                    {
                        aPoint[new Point(x, y - 1)] = Color.Red;
                    }
                    nCount++;
                }
            }

            //TODO:  optimize inner loops to one loop if possible
            Color colorToSet = Color.Transparent;
            for (int y = 1; y < nHeight; y++)
            {
                for (int x = 0; x < nWidth; x++)
                {
                    colorLeft = bitmap.GetPixel(x, y);
                    if (!aPoint.ContainsKey(new Point(x,y)))
                    {
                        Debug.Assert(1>2);
                        //error, we shouldn't have come here...
                        continue;
                    }
                    if (aPoint[new Point(x, y)] != Color.Red)
                    {
                        colorToSet = Color.Black;
                    }
                    else
                    {
                        colorToSet = Color.Red;
                    }
                    bitmap.SetPixel(x, y, colorToSet);
                }
            }
            return _bitmap;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new FindContours2(this);
        }
    }
}
